﻿//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Resource Application Block
//===============================================================================

using System.Configuration;
using EntLibContrib.Resource.Instrumentation;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Unity;
using Microsoft.Practices.ObjectBuilder2;

namespace EntLibContrib.Resource.Configuration.Unity
{
	/// <summary>
	/// This type supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
	/// Represents the process to create the container policies required to create a <see cref="ResourceManager"/>.
	/// </summary>
	public sealed class ResourceManagerPolicyCreator : IContainerPolicyCreator
	{
		#region Fields
		private readonly static ConfigurationReflectionCache reflectionCache = new ConfigurationReflectionCache();
		#endregion

		#region Public Methods
		/// <summary>
		/// Adds the policies required to create the provider specified by <paramref name="configurationObject"/>
		/// to <paramref name="policyList"/>.
		/// </summary>
		/// <param name="policyList">The <see cref="T:Microsoft.Practices.ObjectBuilder2.IPolicyList"/> to which the policies must be added.</param>
		/// <param name="instanceName">The name to use for the instance's policies.</param>
		/// <param name="configurationObject">The <see cref="T:System.Configuration.ConfigurationElement"/> that describes a provider.</param>
		/// <param name="configurationSource">The <see cref="T:Microsoft.Practices.EnterpriseLibrary.Common.Configuration.IConfigurationSource"/> from which additional configuration information
		/// should be retrieved if necessary.</param>
		void IContainerPolicyCreator.CreatePolicies(IPolicyList policyList,
																								string instanceName,
																								ConfigurationElement configurationObject,
																								IConfigurationSource configurationSource)
		{
			// this policy creator will not create policies to support the build plan
			// dynamic method generation.
			// instead, a fixed build plan policy is set

			ResourceManagerData castConfigurationObject = (ResourceManagerData)configurationObject;

			// local vars to avoid getting the configuration object in the delegate's closure
			var resourceManagerName = instanceName;
			var resourceProviderName = castConfigurationObject.ResourceProvider;

			policyList.Set<IBuildPlanPolicy>(
				new DelegateBuildPlanPolicy(
					context =>
					{
						IBuilderContext resourceProviderContext = context.CloneForNewBuild(NamedTypeBuildKey.Make<IResourceProvider>(resourceProviderName), null);
						IResourceProvider resourceProvider = (IResourceProvider)context.Strategies.ExecuteBuildUp(resourceProviderContext);

						ResourceInstrumentationProvider instrumentationProvider = CreateInstrumentationProvider(resourceManagerName, configurationSource);

						return ResourceManagerAssemblerHelper.BuildResourceManager(resourceManagerName,
																																		resourceProvider,
																																		instrumentationProvider);
					}),
				NamedTypeBuildKey.Make<ResourceManager>(resourceManagerName));
		}
		#endregion

		#region Private Methods
		private static ResourceInstrumentationProvider CreateInstrumentationProvider(string name, IConfigurationSource configurationSource)
		{
			ResourceInstrumentationProvider instrumentationProvider = new ResourceInstrumentationProvider();
			new InstrumentationAttachmentStrategy().AttachInstrumentation(name, instrumentationProvider, configurationSource, reflectionCache);

			return instrumentationProvider;
		}
		#endregion
	}
}
